package edu.del.springbootredisbusinesspractice.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import edu.del.springbootredisbusinesspractice.commons.config.RabbitMQConfig;
import edu.del.springbootredisbusinesspractice.commons.exception.OrderException;
import edu.del.springbootredisbusinesspractice.mapper.OrdersMapper;
import edu.del.springbootredisbusinesspractice.mapper.ProductMapper;
import edu.del.springbootredisbusinesspractice.pojo.Orders;
import edu.del.springbootredisbusinesspractice.pojo.Product;
import edu.del.springbootredisbusinesspractice.service.OrdersService;
import edu.del.springbootredisbusinesspractice.service.ProductService;
import edu.del.springbootredisbusinesspractice.utils.SnowflakeIdGenerator;
import edu.del.springbootredisbusinesspractice.utils.cachekey.CacheConstants;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
* @author Del
* @description 订单服务
* @createDate 2025-09-28 09:17:34
*/
@Service
@Slf4j
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders>
    implements OrdersService{

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductService productService;

    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private SnowflakeIdGenerator snowflakeIdGenerator;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final Cache<String, Long> localStockCache  = Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .build();

    @Transactional  // 保证库存扣减和订单创建的原子性，出错回滚
    @Override
    public int placeOrder(int productId, int count) {
        // 1. 拿到商品库存的 Redis Key
        String stockKey = "product:" + productId + ":stock";

        // 懒加载库存
        Long cachedStock = getCachedOrLoadStockFromRedis(productId);


        // 2. 扣减库存
        Long newStock = redisTemplate.opsForValue().decrement(stockKey, count);

        // 3. key 不存在
        if (newStock == null) {
            throw new OrderException(1003, "商品库存未初始化，请联系管理员");
        }

        // 4. 库存不足
        if (newStock < 0) {
            // 手动 回滚
            redisTemplate.opsForValue().increment(stockKey, count);
            throw new OrderException(1002, "商品库存不足");
        }

        // 3. 构建订单对象（只填充必要字段）
        Orders order = new Orders();
        order.setOrderNo(String.valueOf(snowflakeIdGenerator.nextId()));
        order.setProductId((long) productId);
        order.setUserId(1001L);
        order.setTotalAmount(calculateTotalAmount(productId, count));
        order.setQuantity(count);
        order.setStatus(1);
        order.setPaymentMethod("未支付");
        order.setShippingAddress("待填写");
        order.setContactPhone("13800000000");
        order.setContactName("用户");
        order.setCreatedAt(new Date());
        order.setUpdatedAt(new Date());

        // 4. 插入订单到数据库
        int insertResult = ordersMapper.insert(order);
        if (insertResult == 0) {
            // 回滚库存
            redisTemplate.opsForValue().increment(stockKey, count);
            throw new OrderException(1001, "订单创建失败");
        }

        // 4. 发送延迟消息到MQ（30分钟支付超时）
        rabbitTemplate.convertAndSend(
            RabbitMQConfig.ORDER_EXCHANGE,
            RabbitMQConfig.ORDER_DELAY_ROUTING_KEY,
            order,
            message -> {
                // 设置消息的TTL为30分钟
                message.getMessageProperties().setExpiration("60000");
                return message;
            }
        );

        // 5. 更新本地缓存
        localStockCache.put(stockKey, (long) newStock.intValue());

        log.info("【下单成功】订单已创建，等待支付，orderNo: {}", order.getOrderNo());
        return Integer.parseInt(order.getId().toString());
    }

    /**
     * 支付成功回调
     */
    @Transactional
    public boolean paySuccess(String orderNo) {
        Orders order = ordersMapper.selectByOrderNo(orderNo);
        if (order == null) {
            throw new OrderException(1004, "订单不存在");
        }

        if (order.getStatus() != 1) {
            // 订单不是未支付状态，可能是已支付或已取消
            throw new OrderException(1005, "订单状态异常");
        }

        // 更新订单状态为已支付
        order.setStatus(2);
        order.setPaymentMethod("在线支付");
        order.setUpdatedAt(new Date());
        int updateResult = ordersMapper.updateById(order);

        if (updateResult > 0) {
            log.info("【支付成功】订单支付完成，orderNo: {}", orderNo);

            // 发送支付成功消息到MQ，触发后续业务（发货、通知等）
            rabbitTemplate.convertAndSend(
                RabbitMQConfig.ORDER_EXCHANGE,
                RabbitMQConfig.ORDER_PAID_ROUTING_KEY,
                order
            );
            return true;
        }
        return false;
    }


    @Transactional
    @Override
    public boolean cancelOrder(String orderNo) {
        // 1. 查询订单
        Orders order = ordersMapper.selectByOrderNo(orderNo);
        if (order == null) {
            throw new OrderException(1004, "订单不存在");
        }

        // 2. 检查订单状态是否允许取消
        if (order.getStatus() != 1 && order.getStatus() != 2) {
            throw new OrderException(1006, "当前订单状态不允许取消");
        }

        // 3. 保存旧状态
        int oldStatus = order.getStatus();

        // 4. 更新订单状态为已取消
        order.setStatus(5); // 5 代表已取消
        order.setUpdatedAt(new Date());
        int updateResult = ordersMapper.updateById(order);

        if (updateResult > 0) {
            // 5. 如果原来是未支付状态，恢复库存
            if (oldStatus == 1) {
                String stockKey = String.format(CacheConstants.STOCK_KEY_PREFIX, order.getProductId());
                int count = order.getQuantity() != null ? order.getQuantity() : 1;
                redisTemplate.opsForValue().increment(stockKey, count);
                // 回复本地缓存
                 localStockCache.put(stockKey, Long.valueOf(Objects.requireNonNull(redisTemplate.opsForValue().get(stockKey))));

                log.info("【取消订单】已恢复库存，productId: {}, 数量: {}", order.getProductId(), count);
            }

            // 6. 注册事务同步器，在事务提交成功后发送消息
            TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        try {
                            // 事务已提交，此时发送消息是安全的
                            rabbitTemplate.convertAndSend(
                                RabbitMQConfig.ORDER_EXCHANGE,
                                RabbitMQConfig.ORDER_CANCEL_ROUTING_KEY,
                                order
                            );
                            log.info("【取消订单】事务提交成功，已发送取消订单消息，orderNo: {}", orderNo);
                        } catch (Exception e) {
                            log.error("【取消订单】事务提交后发送消息失败，orderNo: {}", orderNo, e);
                        }
                    }
                }
            );
            return true;
        } else {
            return false;
        }
    }

    @Override
    public List<Orders> UnpaidOrderList(Integer id) {
        return ordersMapper.unpaidOrderList(id);
    }


    @Override
    public Orders getByOrderNo(String orderNo) {
        return ordersMapper.selectByOrderNo(orderNo);
    }



    /**
     * 数据库查询该商品当前价格
     */
    private BigDecimal calculateTotalAmount(int productId, int count) {
        Product product = productService.getProductById(productId);
        // 获取真实价格
        BigDecimal unitPrice = new BigDecimal(product.getPrice().longValue());
        return unitPrice.multiply(new BigDecimal(count));
    }

    /**
     * 获取商品库存，如果本地缓存没有，则从 Redis 加载并缓存
     */
    private Long getCachedOrLoadStockFromRedis(int productId) {
        String stockKey = String.format(CacheConstants.STOCK_KEY_PREFIX, productId);

        // 1. 先查本地缓存
        Long cachedStock = localStockCache.getIfPresent(stockKey);
        if (cachedStock != null) {
            return cachedStock;
        }

        // 2. 本地没有，查 Redis
        String redisStockStr = redisTemplate.opsForValue().get(stockKey);
        if (redisStockStr == null) {
            throw new OrderException(1003, "商品库存未初始化，请联系管理员");
        }

        // 3. Redis 有，解析并放入本地缓存
        cachedStock = Long.valueOf(redisStockStr);
        localStockCache.put(stockKey, cachedStock);

        return cachedStock;
    }


    @PostConstruct
    private void initStockCache() {
        List<Product> products = productMapper.selectList(null);

        for (Product product : products) {
            // 缓存库存
            redisTemplate.opsForValue().set(String.format(CacheConstants.STOCK_KEY_PREFIX, product.getId()), String.valueOf(product.getStock()));
            // 本地缓存
            localStockCache.put(String.format(CacheConstants.STOCK_KEY_PREFIX, product.getId()), (long) product.getStock());
        }
    }
}




